﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: Windows Server Roles and Features view model
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------



using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class WindowsServerRoleOrFeatureViewModel : ViewModelBase, IDataErrorInfo
    {
        private readonly List<string> modelRolesAndFeatures;
        private readonly RoleOrFeature roleOrFeature;
        bool? isChecked = false;
        WindowsServerRoleOrFeatureViewModel parent;
        private readonly WindowsServerRolesAndFeaturesViewModel parentContainer;

        public List<WindowsServerRoleOrFeatureViewModel> Children { get; private set; }

        public bool IsInitiallySelected { get; private set; }

        public string DisplayName
        {
            get { return OSFeatureDisplayNameEnumHelper.GetName(this.roleOrFeature.DisplayName); }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public WindowsServerRoleOrFeatureViewModel(List<string> modelRolesAndFeatures, RoleOrFeature roleOrFeature, WindowsServerRolesAndFeaturesViewModel parentContainer)
        {
            this.modelRolesAndFeatures = modelRolesAndFeatures;
            this.roleOrFeature = roleOrFeature;
            this.parentContainer = parentContainer;
            this.Children = new List<WindowsServerRoleOrFeatureViewModel>();
            if (this.modelRolesAndFeatures.Contains(this.roleOrFeature.Name))
            {
                this.isChecked = true;
                this.IsInitiallySelected = true;
            }
            else
            {
                this.isChecked = false;
                this.IsInitiallySelected = false;
            }

            foreach (RoleOrFeature rf in roleOrFeature.Children.Values)
            {
                var rfViewModel = new WindowsServerRoleOrFeatureViewModel(this.modelRolesAndFeatures, rf, parentContainer);
                this.Children.Add(rfViewModel);
            }
            this.Initialize();
        }

        private void Initialize()
        {
            foreach (var child in this.Children)
            {
                child.parent = this;
                child.Initialize();
            }
        }

        #region IsChecked

        /// <summary>
        /// Gets/sets the state of the associated UI toggle (ex. CheckBox).
        /// The return value is calculated based on the check state of all
        /// children.  Setting this property to true or false
        /// will set all children to the same check state, and setting it 
        /// to any value will cause the parent to verify its check state.
        /// </summary>
        public bool? IsChecked
        {
            get { return this.isChecked; }
            set { this.SetIsChecked(value, true, true); }
        }

        void SetIsChecked(bool? value, bool updateChildren, bool updateParent)
        {
            if (value == this.isChecked)
                return;

            this.isChecked = value;

            if (this.isChecked.GetValueOrDefault())
            {
                if (!this.modelRolesAndFeatures.Contains(this.roleOrFeature.Name))
                {
                    this.modelRolesAndFeatures.Add(this.roleOrFeature.Name);
                }
            }
            else
            {
                this.modelRolesAndFeatures.RemoveAll(name => string.Compare(name, this.roleOrFeature.Name, StringComparison.OrdinalIgnoreCase) == 0);
            }
            
            this.parentContainer.OnPropertyChanged(WindowsServerRolesAndFeaturesViewModel.PropertyNames.Summary);

            if (updateChildren && this.isChecked.HasValue)
                this.Children.ForEach(c => c.SetIsChecked(this.isChecked, true, false));

            if (updateParent && this.parent != null)
                this.parent.VerifyCheckState();

            this.OnPropertyChanged("IsChecked");
        }

        void VerifyCheckState()
        {
            bool? state = null;
            for (int i = 0; i < this.Children.Count; ++i)
            {
                bool? current = this.Children[i].IsChecked;
                if (i == 0)
                {
                    state = current;
                }
                else if (state != current)
                {
                    state = null;
                    break;
                }
            }
            this.SetIsChecked(state, false, true);
        }

        #endregion // IsChecked       

        public string this[string columnName]
        {
            get { return null; }
        }

        public string Error { get; set; }
        
    }


    public class WindowsServerRolesAndFeaturesViewModel : TreeViewItemViewModel, IDataErrorInfo, IProduceValidationResults
    {
        private readonly List<String> windowsServerRolesAndFeatures;
        private readonly ObservableCollection<WindowsServerRoleOrFeatureViewModel> windowsServerRoleViewModels;
        private readonly ObservableCollection<WindowsServerRoleOrFeatureViewModel> windowsServerFeatureViewModels;
        private readonly ObservableCollection<string> compatibleOperatingSystems;
        private string selectedCompatibleOperatingSystem;

        private readonly WindowsRoleOrFeatures rolesAndFeatures;
        
        public static class PropertyNames
        {            
            public const string Summary = "Summary";
            public const string WindowsServerRoleViewModels = "WindowsServerRoleViewModels";
            public const string WindowsServerFeatureViewModels = "WindowsServerFeatureViewModels";
            public const string CompatibleOperatingSystems = "CompatibleOperatingSystems";
            public const string SelectedCompatibleOperatingSystem = "SelectedCompatibleOperatingSystem";
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public WindowsServerRolesAndFeaturesViewModel(List<String> windowsServerRolesAndFeatures, TreeViewItemViewModel parentItemViewModel)
            : base(parentItemViewModel, true)
        {
            this.windowsServerRolesAndFeatures = windowsServerRolesAndFeatures ?? new List<String>();
            this.windowsServerRoleViewModels = new ObservableCollection<WindowsServerRoleOrFeatureViewModel>();
            this.windowsServerFeatureViewModels = new ObservableCollection<WindowsServerRoleOrFeatureViewModel>();
           
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();

            this.compatibleOperatingSystems = new ObservableCollection<string>
                {
                    OSFeatureCompatibleOSHelper.GetName(OSFeatureCompatibleOS.WindowsServer2012R2),
                    OSFeatureCompatibleOSHelper.GetName(OSFeatureCompatibleOS.WindowsServer2012),
                    OSFeatureCompatibleOSHelper.GetName(OSFeatureCompatibleOS.WindowsServer2008R2)
                };
            this.selectedCompatibleOperatingSystem = this.compatibleOperatingSystems[0]; //Default is Blue

            this.rolesAndFeatures = WindowsRoleOrFeatures.GetWindowsRoleOrFeatures();     
            this.ConstructRolesAndFeatures(OSFeatureCompatibleOS.WindowsServer2012R2);
        }   

        public string Summary
        {
            get { return "Roles & Features (" + this.windowsServerRolesAndFeatures.Count() + ")"; }
        }       

        public ObservableCollection<WindowsServerRoleOrFeatureViewModel> WindowsServerRoleViewModels
        {
            get { return this.windowsServerRoleViewModels; }
        }

        public ObservableCollection<WindowsServerRoleOrFeatureViewModel> WindowsServerFeatureViewModels
        {
            get { return this.windowsServerFeatureViewModels; }
        }

        public  ObservableCollection<string> CompatibleOperatingSystems
        {
            get { return this.compatibleOperatingSystems; }
        }


        public string SelectedCompatibleOperatingSystem
        {
            get { return this.selectedCompatibleOperatingSystem; }
            set
            {
                if (value != null)
                {
                    this.selectedCompatibleOperatingSystem = value;                  
                    OSFeatureCompatibleOS os;
                    if (string.CompareOrdinal(this.selectedCompatibleOperatingSystem, OSFeatureCompatibleOSHelper.GetName(OSFeatureCompatibleOS.WindowsServer2008R2)) == 0)
                    {
                        os = OSFeatureCompatibleOS.WindowsServer2008R2;                        
                    }
                    else if (string.CompareOrdinal(this.selectedCompatibleOperatingSystem,OSFeatureCompatibleOSHelper.GetName(OSFeatureCompatibleOS.WindowsServer2012)) == 0)
                    {
                        os = OSFeatureCompatibleOS.WindowsServer2012;
                    }
                    else
                    {
                        os = OSFeatureCompatibleOS.WindowsServer2012R2;
                    }
                    this.windowsServerRoleViewModels.Clear();
                    this.windowsServerFeatureViewModels.Clear();
                    this.ConstructRolesAndFeatures(os);
                    this.OnPropertyChanged(PropertyNames.WindowsServerRoleViewModels);
                    this.OnPropertyChanged(PropertyNames.WindowsServerFeatureViewModels);                                                     
                }
                this.OnPropertyChanged(PropertyNames.SelectedCompatibleOperatingSystem);              
            }
        }

        private void ConstructRolesAndFeatures(OSFeatureCompatibleOS os)
        {
            //Roles
            foreach (var role in this.rolesAndFeatures.Roles[os].Values)
            {
                WindowsServerRoleOrFeatureViewModel  roleModel = new WindowsServerRoleOrFeatureViewModel(this.windowsServerRolesAndFeatures, role, this);               
                this.windowsServerRoleViewModels.Add(roleModel);
            }
            //Features
            foreach (var feature in this.rolesAndFeatures.Features[os].Values)
            {
                WindowsServerRoleOrFeatureViewModel  featureViewModel = new WindowsServerRoleOrFeatureViewModel(this.windowsServerRolesAndFeatures, feature, this);
                this.windowsServerFeatureViewModels.Add(featureViewModel);
            }            
        }


        public string this[string columnName]
        {
            get { return null; }
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error           
        }   
    }
}
